#include <func.h>
#define MAXEVENTS 10
typedef struct fd1{
    int clientfd;
    int fd;    //用户需要下载的文件（通过open在本地创建）的 文件描述符
}client_t;
typedef  struct train{
    int length;
    char date[1024];
}train_t;
void* cdfunc(void * arg){

}
void* lsfunc(void * arg){

}
void* pwdfunc(void * arg){
    printf("do pwdfunction\n");
    client_t* c = (client_t*)arg;
    char buf[1024]={0};
    recv(c->clientfd,buf,sizeof(buf),0);
    puts(buf);
    pthread_exit((void*)1);

}


int recvn(int fd, const void * buf, int len)                                  
{
    int left = len;
    char * pbuf = (char *)buf;
    int ret;
    while(left > 0) {
        ret = recv(fd, pbuf, left, 0);
        if(ret < 0) {
            perror("send");
            break;
        } else {
            pbuf += ret;
            left -= ret;
        }
    }
    return len - left;
}


void getsFunction_bigfile(int clientfd,int filefd,off_t filesize,off_t filexistmark)
{
        //接受文件
        char * pbuf = (char *) mmap(NULL,filesize,PROT_READ | PROT_WRITE, MAP_SHARED, filefd, 0);

        int ret = recv(clientfd,pbuf + filexistmark,filesize - filexistmark,MSG_WAITALL);
        printf("recvn:%d charactor\n",ret);
        perror("big file recv");
        printf("recv big file over\n");
        close(filefd);
        munmap(pbuf,filexistmark );

}


void getsFunction_smallfile(int clientfd,int filefd,off_t filesize){
    printf("clientfd:%d,filefd:%d,filesize:%ld\n",clientfd,
           filefd,filesize);
    char buf[1024] = {0};
    memset(buf,0,1024);
    int retval;
    off_t slice = filesize/100;
    off_t downloadsize=0;
    off_t lastsize = 0;
    while(downloadsize<filesize){
        memset(buf,0,sizeof(buf));
        retval = recv(clientfd,buf,sizeof(buf),0);
        downloadsize+=retval;
        if(downloadsize - lastsize>slice){
            printf(">> download percent:%5.2lf%%\n",(double)downloadsize/filesize*100);
            lastsize = downloadsize;
        }
        retval = write(filefd,buf,retval);
        ERROR_CHECK(retval,-1,"write");
    }
    printf(">>download percent:100%%\n");
    printf("getsfunc is over!\n");
    close(filefd);
}
void *getsfunc(void * arg)
{

    client_t * clientdata = (client_t*)arg;
    int clientfd = clientdata->clientfd;
    int filefd = clientdata-> fd;
    printf("clientfd:%d,filefd:%d\n",clientfd,filefd);
    printf("p->clientfd:%d,p->filefd:%d\n",clientdata->clientfd,clientdata->fd);

   // char buf[1024] = {0};
   // memset(buf,0,sizeof(buf));
   // recv(clientfd,buf,sizeof(buf),0);
   // puts(buf);
   // memset(buf,0,sizeof(buf));
    
    
    int ret;
    off_t filexistmark = 0; //用于记录文件当前位置，及偏移量
    struct stat file_stat;
    fstat(filefd,&file_stat);
    filexistmark = file_stat.st_size;

    //接受文件总大小
    int filesizeoflength = 0;
    off_t filesize = 0;
    ret = recv(clientfd,&filesizeoflength,4,MSG_WAITALL);
    printf(">>>>>>>>>>>>filesizeoflenth%d\n",filesizeoflength);
    ret = recv(clientfd,&filesize,filesizeoflength,MSG_WAITALL);
    printf(">>>>>>>>>>>>filesize:%ld\n",filesize);

    //发送偏移量
    ret = send(clientfd,&filexistmark,8,0);
    printf("send %d charactor\n",ret);
    printf("send file offset:%ld\n",filexistmark);

    off_t filesurplus = filesize - filexistmark;
    //判断大文件小文件
    if(filesurplus < (long)100* 1024){
        printf("small file\n");
        lseek(filefd,SEEK_SET,filexistmark);
        getsFunction_smallfile(clientfd,filefd,filesurplus);
    }else{
        printf("big file\n");
        ftruncate(filefd,filesize);
        printf("ftruncate");
        getsFunction_bigfile(clientfd,filefd,filesize,filexistmark);
    }
    pthread_exit((void*)1);
}

int sendn(int fd, const void * buf, int len)                                  
{
    int left = len;
    char * pbuf = (char *)buf;
    int ret;
    while(left > 0) {
        ret = send(fd, pbuf, left, 0);
        if(ret < 0) {
            perror("send");
            break;
        } else {
            pbuf += ret;
            left -= ret;
        }
    }
    return len - left;
}


void putsFunction_bigfile(int clientfd,int filefd,off_t filesize,off_t filexistmark)
{
    int ret = 0;
    //发送文件内容
    char * pbuf = (char *)mmap(NULL,filesize,PROT_READ | PROT_WRITE,MAP_SHARED, filefd, 0);
    perror("mmap");
    ret = send(clientfd,pbuf+filexistmark,filesize - filexistmark,0);
    printf("putsFunction_bigfile:send:%d\n",ret);
    perror("putsFunction_bigfile:send");
    printf("big file send over!\n");
    close(filefd);
    munmap(pbuf, filesize);

}

void putsFunction_smallfile(int clientfd, int filefd, off_t filesize){
    printf("clientfd:%d,filefd:%d,filesize:%ld\n",clientfd,
           filefd,filesize);
    train_t train;
    memset(&train,0,sizeof(train));
    printf("begin!\n");
    char buf[1024]={0};
    memset(buf,0,sizeof(buf));
   // int length = st.st_size;
   // sprintf(buf,"%d",length);
   // printf("buf:%s\n",buf);
   // send(clientfd,buf,strlen(buf),0);
   // printf("send:%s\n",buf);
    off_t sendsize = 0;
    //memset(buf,0,sizeof(buf));
    while(sendsize<filesize){
        int retval = read(filefd,buf,sizeof(buf));
        retval = send(clientfd,buf,retval,0);
        printf("retval:%d\n",retval);
        sendsize+=retval;
        memset(buf,0,sizeof(buf));
    }
    close(filefd);
    printf("file send over!\n");
}



void *putsfunc(void * arg){

    client_t * clientdata = (client_t*)arg;
    int clientfd = clientdata->clientfd;
    int filefd = clientdata->fd;
    char buf[1024] = {0};
    memset(buf,0,sizeof(buf));
    recv(clientfd,buf,sizeof(buf),0);
    puts(buf);
    memset(buf,0,sizeof(buf));
    int ret;
    train_t train;

    //发送长度
    memset(&train,0,sizeof(train));
    struct stat file_stat;
    fstat(filefd,&file_stat);
    off_t filesize = file_stat.st_size;
    train.length = sizeof(off_t);
    strncpy(train.date,(char*)&filesize,train.length);
    ret = sendn(clientfd,&train,4 + train.length);
    printf("file length:%ld\n",file_stat.st_size);

    //接受文件偏移量
    off_t filexistmark = 0;
    ret = recv(clientfd,&filexistmark,8,0);
    printf("recv file offset:%ld\n",filexistmark);

    off_t filesurplus = filesize - filexistmark;

    //传文件选择
    if(filesurplus < (long)100*1024){
        printf("small file\n");
        lseek(filefd,SEEK_SET,filexistmark);
        putsFunction_smallfile(clientfd,filefd,filesurplus);
    }else{
        printf("big file\n");
        putsFunction_bigfile(clientfd,filefd,filesize,filexistmark);
    }
}

/*
void* putsfunc(void * arg){
    client_t* c = (client_t*)arg;
    char buf[1024]={0};
    memset(buf,0,sizeof(buf));
    recv(c->clientfd,buf,sizeof(buf),0);
    puts(buf);
    memset(buf,0,sizeof(buf));
    printf("do putsfunc\n");
    train_t train;
    memset(&train,0,sizeof(train));
    struct stat st;
    fstat(c->fd,&st);
    printf(">>file length:%ld\n",st.st_size);
    train.length = st.st_size;
    send(c->clientfd,&train,4,0);
    printf("send:%d\n",train.length);
    off_t sendsize = 0;
    while(sendsize<st.st_size){
        int retval = read(c->fd,buf,sizeof(buf));
        retval = send(c->clientfd,buf,retval,0);
        sendsize+=retval;
        memset(buf,0,sizeof(buf));
    }
    close(c->fd);
    printf("file sendover");
    pthread_exit((void*)1);
}

void* getsfunc(void * arg){
    printf("do getsfunction\n");
    client_t* c = (client_t*)arg;
    char buf[1024]={0};
    memset(buf,0,sizeof(buf));
    //接受文件大小
    off_t filesize;
    recv(c->clientfd,&filesize,4,0);
    int retval;
    printf("filesize:%ld\n",filesize);
    off_t slice = filesize/100;
    off_t downloadsize = 0;
    off_t lastsize = 0;
    while(downloadsize<filesize){
        memset(buf,0,sizeof(buf));
        retval = recv (c->clientfd,buf,sizeof(buf),0);
        downloadsize+=retval;
        if(downloadsize - lastsize >slice){
            printf(">> download percent:%5.2lf%%\n",(double)downloadsize/filesize *100 );
            lastsize = downloadsize;
        }
        retval = write(c->fd,buf,retval);
        ERROR_CHECK(retval,-1,"write");

    }
    printf(">>downloadsize percent:100%%\n");
    printf("getsfunc is over!\n");
    close(c->fd);
    pthread_exit((void*)1);
}

*/

void* rmfunc(void * arg){

}
void* mkdirfunc(void * arg){

}
int main()
{
    char buf[1024]={0};
    memset(buf,0,sizeof(buf));
    int clientfd = socket(AF_INET,SOCK_STREAM,0);
    client_t c;
    c.clientfd=clientfd;
    struct sockaddr_in clientaddr;
    clientaddr.sin_family=AF_INET;
    clientaddr.sin_port=htons(8888);
    clientaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
    int ret = connect(clientfd,(struct sockaddr*)&clientaddr,sizeof(clientaddr));
    ERROR_CHECK(ret,-1,"connect");
    printf("plea input account and passwd.\n");
    read(STDIN_FILENO,buf,sizeof(buf));
    send(clientfd,buf,strlen(buf),0);
    memset(buf,0,sizeof(buf));
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    recv(clientfd,buf,sizeof(buf),0);
    puts(buf);
    int epfd = epoll_create(MAXEVENTS);
    struct epoll_event peventlist[MAXEVENTS]; 
    memset(&peventlist,0,sizeof(peventlist));
    struct epoll_event evt;

    evt.data.fd=EPOLLIN;
    evt.events=EPOLLIN|EPOLLET;
    epoll_ctl(epfd,EPOLL_CTL_ADD,EPOLLIN,&evt);
    memset(buf,0,sizeof(buf));
    pthread_t pid;
    char filename[1024]={0};
    memset(filename,0,sizeof(filename));
    char order[1024]={0};
    memset(order,0,sizeof(filename));
    while(1){
        memset(filename,0,sizeof(filename));
        memset(order,0,sizeof(order));
        int u = 0;//u用来辅助组成命令
        int x = 0;//x用来辅助组成文件名
        int z = 0;
        int t = 0;
        int ret = epoll_wait(epfd,peventlist,MAXEVENTS,-1);
        printf("ret:%d\n",ret);
        if(ret>0){
            for(int idx = 0;idx<ret;idx++){
                printf("peventlist[idx].event:%d\n",peventlist[idx].events);
                if(peventlist[idx].events & EPOLLIN){
                    memset(buf,0,sizeof(buf));
                    int ret = read(STDIN_FILENO,buf,sizeof(buf));//从标准输入中读取命令
                    send(clientfd,buf,strlen(buf),0);//发送该命令给值服务器
                    printf("send:%s\n",buf);
                    for(;z<ret;z++){//寻找命令以及文件名
                        while(buf[z]!=32&&z<ret-1){//32为ASCII码中空值，寻找第一个不为空的值，接下来几个连起来就是命令
                            order[u]=buf[z];//组成命令
                            z++;
                            u++;
                            if(buf[z]==32||z==ret-1){
                                t = z;
                                z =ret;
                            }
                        }
                        puts(order);
                    }//文件名和命令名的查找到此为止。
                    for(;t<ret;t++){//有文件名的话 肯定在命令后面 接着上面的z值继续查询就行
                        while(buf[t]!=32&&t<ret-1){
                            filename[x]=buf[t];//组成文件名
                            x++;
                            t++;
                            if(buf[t]==32||t==ret-1){//如果等于空或者到头了 就将z设置为ret值，结束所有嵌套循环
                                t = ret;
                            }
                        } 
                    }
                    puts(filename);
                    //根据命令进入不同线程功能
                    if(u == 2 && order[0] == 'c' && order[1] == 'd'){
                        pthread_create(&pid,NULL,cdfunc,&c);
                    }else if(u == 2 && order[0] == 'l' && order[1] == 's'){
                        pthread_create(&pid,NULL,lsfunc,&c);
                    }else if(u == 3 && order[0] == 'p' && order[1] == 'w' && order[2] == 'd'){
                        pthread_create(&pid,NULL,pwdfunc,&c);
                    }else if(u == 4 && order[0] == 'p' && order[1] == 'u' && order[2] == 't' && order[3] == 's'){
                        printf("execute putsfunc\n");
                        int fd = open(filename,O_RDWR);
                        c.fd = fd;
                        c.clientfd = clientfd;
                        pthread_create(&pid,NULL,putsfunc,&c);
                    }else if(u == 4 && order[0] == 'g' && order[1] == 'e' && order[2] == 't' && order[3] == 's'){
                        printf("execute getsfunc\n");
                        int fd = open(filename,O_RDWR,0666);
                        if(-1 == fd){
                            fd = open(filename,O_RDWR | O_CREAT,0666);
                        }
                        printf("fd:%d\n",fd);
                        c.fd =fd;
                        c.clientfd = clientfd;
                        pthread_create(&pid,NULL,getsfunc,&c);
                    }else if(u == 2 && order[0] == 'r' && order[1] == 'm'){
                        pthread_create(&pid,NULL,rmfunc,&c);
                    }else if(u == 5 && order[0] == 'm' && order[1] == 'k' && order[2] == 'd' && order[3] == 'i' && order[4] == 'r'){
                        pthread_create(&pid,NULL,mkdirfunc,&c);
                    }else if(u == 4 && order[0] == 'e' && order[1] == 'x' && order[2] == 'i' && order[3] == 't'){
                        pthread_join(pid,NULL);
                        exit(1);
                    }else{
                        printf("this order is illegal.\n");
                    }
                }
            }
        }
    }

    pthread_join(pid,NULL);
    return 0;
}
